package com.pro.common.user.task.service;

import java.util.*;

import java.time.LocalDateTime;

import com.pro.common.api.model.BaseModel;
import com.pro.common.api.user.intf.UserFeignClient;
import com.pro.common.api.user.model.IUser;
import com.pro.common.api.user.model.db.User;
import com.pro.common.api.user.task.enums.EnumUserTaskStatus;

import com.pro.common.api.user.task.model.db.UserTask;
import com.pro.common.api.user.task.model.db.UserTaskStep;
import com.pro.common.api.user.task.model.db.UserTaskStepCall;
import com.pro.common.api.user.task.model.dto.UserTaskStepCallNotifyDTO;
import com.pro.common.api.user.task.model.dto.UserTaskStepCreateDTO;
import com.pro.common.api.user.task.model.request.UserTaskCreatRequest;
import com.pro.common.api.user.task.model.request.UserTaskStepSubmitRequest;
import com.pro.common.user.task.model.mapstruct.UserTaskMapper;
import com.pro.framework.api.util.CollUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.stream.Collectors;

/**
 * 用户任务服务
 */
@Service
@Slf4j
@AllArgsConstructor
public class UserTaskUnitService {
    private UserTaskService taskService;
    private UserTaskStepService taskStepService;
    private UserTaskStepCallService taskStepCallService;
    private UserTaskMapper userTaskMapper;
    private UserFeignClient<? extends User> userFeignClient;

    @Transactional(rollbackFor = Exception.class)
    public void submitStepsNotify(List<UserTaskStepSubmitRequest> requestSteps) {
        LocalDateTime now = LocalDateTime.now();
        Map<Long, UserTaskStepSubmitRequest> requestStepMap = CollUtils.listToMap(requestSteps, UserTaskStepSubmitRequest::getId);

        List<UserTaskStep> stepOlds = taskStepService.listByIds(requestStepMap.keySet());
        stepOlds = stepOlds.stream().filter(s -> EnumUserTaskStatus.RUNNING.equals(s.getStatus()) || EnumUserTaskStatus.PENDING.equals(s.getStatus())).toList();

        List<Long> endTaskIds = stepOlds.stream().map(UserTaskStep::getTaskId).toList();
        Map<Long, UserTask> taskMap = endTaskIds.isEmpty() ? Collections.emptyMap() : taskService.idMap(endTaskIds);
        List<UserTaskStep> updateSteps = stepOlds.stream().map(stepOld -> {
            UserTaskStepSubmitRequest requestStep = requestStepMap.get(stepOld.getId());


            UserTaskStep update = new UserTaskStep();
            update.setId(stepOld.getId());
            userTaskMapper.update(requestStep, update);
            userTaskMapper.update(requestStep, stepOld);
            update.setStartedTime(now);
            if (EnumUserTaskStatus.SUCCESS.equals(requestStep.getStatus())) {
                update.setFinishedTime(now);
            }
            List<UserTaskStepCallNotifyDTO> userTaskStepCalls = requestStep.getUserTaskStepCalls();
            update.setUserTaskStepCalls(userTaskStepCalls.stream().map(requestStepCall -> {
                UserTaskStepCall call = userTaskMapper.build(requestStepCall);
                userTaskMapper.update(stepOld, call);
                return call;
            }).toList());
            Integer stepOrderNext = null;
            UserTaskStepCreateDTO nextStepRequest = requestStep.getNextStep();
            if (nextStepRequest != null) {
                stepOrderNext = stepOld.getStepOrder() + 1;
                UserTaskStep nextStep = new UserTaskStep();
//            nextStep.setTaskId(stepOld.getTaskId());
//            nextStep.setUserId(stepOld.getUserId());
//            nextStep.setTaskType(stepOld.getTaskType());
//            userTaskMapper.update(stepOld, nextStep);
//            nextStep.setServiceName(null);
//            nextStep.setStepName(null);
//            nextStep.setOutputInfo(null);
                userTaskMapper.update(nextStepRequest, nextStep);
                nextStep.setStepOrder(stepOrderNext);
                nextStep.setUserId(stepOld.getUserId());
                nextStep.setTaskId(stepOld.getTaskId());
                nextStep.setTaskType(stepOld.getTaskType());
                nextStep.setCreateBy(stepOld.getCreateBy());

//            nextStep.setStepName(nextStepRequest.getStepName());
//            nextStep.setServiceName(nextStepRequest.getStepName());

                nextStep.setStatus(EnumUserTaskStatus.PENDING);
//            nextStep.setStartedTime(new LocalDateTime());
//            nextStep.setFinishedTime(new LocalDateTime());
                nextStep.setInputInfo(stepOld.getOutputInfo());
//            nextStep.setOutputInfo("");
//            nextStep.setErrorMsg("");
//            nextStep.setUserTaskStepCalls(new ArrayList<>());
//            nextStep.setNextStep(new UserTaskStep());
                update.setNextStep(nextStep);
            }


            boolean successFlag = EnumUserTaskStatus.SUCCESS.equals(requestStep.getStatus());
            boolean successEndFlag = successFlag && null == nextStepRequest;
            boolean failEndFlag = EnumUserTaskStatus.FAILED.equals(requestStep.getStatus());
            // 更新主任务
            UserTask userTask = taskMap.get(stepOld.getTaskId());
            UserTask updateTask = new UserTask();
//            if (EnumUserTaskStatus.PENDING.equals(userTask.getStatus())) {
//            }
            updateTask.setStatus(EnumUserTaskStatus.RUNNING);
            updateTask.setErrorMsg("");

            updateTask.setId(userTask.getId());
            if (successFlag) {
                updateTask.setCurrentStep(stepOrderNext);
            }
            if (successEndFlag || failEndFlag) {
                updateTask.setStatus(stepOld.getStatus());
                updateTask.setFinishedTime(now);
            }
            if (failEndFlag) {
                updateTask.setErrorMsg(stepOld.getErrorMsg());
            }
            update.setUserTask(updateTask);
            return update;
        }).toList();

        taskService.updateBatchById(updateSteps.stream().map(UserTaskStep::getUserTask).toList());
        taskStepService.updateBatchById(updateSteps);
        taskStepService.saveBatch(updateSteps.stream().map(UserTaskStep::getNextStep).filter(Objects::nonNull).collect(Collectors.toList()));
        taskStepCallService.saveBatch(updateSteps.stream().flatMap(s -> s.getUserTaskStepCalls().stream()).collect(Collectors.toList()));
    }

    public void create(List<UserTaskCreatRequest> requestTasks) {
        LocalDateTime now = LocalDateTime.now();
        List<Long> userIds = requestTasks.stream().map(UserTaskCreatRequest::getUserId).toList();
        //noinspection unchecked
        Map<Long, ? extends User> userMap = userFeignClient.idMap(userIds);
        List<UserTask> tasks = requestTasks.stream().map(requestTask -> {
            UserTask userTask = userTaskMapper.build(requestTask);
            userTask.setStatus(EnumUserTaskStatus.RUNNING);
            User user = userMap.get(userTask.getUserId());
            userTaskMapper.update(user, userTask);

            UserTaskStepCreateDTO requestStep = requestTask.getStep();
            UserTaskStep userTaskStep = new UserTaskStep();
            userTaskStep.setUserId(userTask.getUserId());
//            userTaskStep.setTaskId(0L);
            userTaskStep.setStepOrder(1);
            userTaskStep.setTaskType(requestTask.getTaskType());
            userTaskStep.setStepName(requestStep.getStepName());
            userTaskStep.setServiceName(requestStep.getServiceName());
            userTaskStep.setStatus(EnumUserTaskStatus.PENDING);
            userTaskStep.setStartedTime(now);
            userTaskStep.setInputInfo(requestStep.getInputInfo());
            userTaskStep.setCreateBy(requestTask.getCreateBy());
            userTask.setUserTaskSteps(List.of(userTaskStep));
            return userTask;
        }).toList();
        taskService.saveBatch(tasks);
        tasks.forEach(task->task.getUserTaskSteps().forEach(s->s.setTaskId(task.getId())));
        taskStepService.saveBatch(tasks.stream().flatMap(t -> t.getUserTaskSteps().stream()).collect(Collectors.toList()));
    }
}
